home *** CD-ROM | disk | FTP | other *** search
- //
- // Ear Workout, by Ben Crowell
- //
- // Version history:
- // version 1.0 - 21 Nov 95
- // Includes two workouts: chords and intervals.
- // version 2.0 - 9 Jan 96
- // New workout: singing intervals (currently works ok
- // with whistling, but not as well with singing).
- //
- // Ideas for new workouts:
- // Play scale, play chord, they identify chord w.r.t. key.
- // Rhythm: reading? rhythmic canons? cross-rhythms?
- // Tetrachords; identify by mac-style click and select
- // across the scale
- // Identify inversions of chords.
- //
- // Improvements to make:
- // Staff notation could look a lot better.
- // Misc possible improvements in chords: see ear_chords.cp
- // Should store waveforms in a resource, instead of computing them
- // when we start up.
- // Implementation of volume control is not so great: should
- // highlight the previous volume selection.
- // Timbre of synthesized notes is not exactly beautiful.
- // Subroutine bail_out() should give a dialog box, not just write to a file.
- //
- // Bugs:
- // If it's already running (no workout open), and you double-click
- // on it in the finder, you get a watch cursor that never changes
- // to an arrow. Also may crash.
- //
- //
-
- #include <string.h>
- #include <stdlib.h>
- #include <stdio.h>
- #include <math.h>
-
- #include <OSUtils.h>
- #include <QuickDraw.h>
- #include <Sound.h>
-
- #define NEED_MAC_STUFF 1
-
- #include "Ninkasi:C++ util:generic.h"
- #include "Ninkasi:C++ util:complete_window.h"
- #include "ear_defines.h"
- #include "ear_globals.h"
- #include "ear_prototypes.h"
-
- void init_mac_stuff();
- void wrap_it_up();
- void set_up_menus(int resource_id,int apple_menu_id);
- void event_loop();
- void do_mouse_down(EventRecord *my_event);
- void do_controls(WindowPtr window,Point where,EventRecord *my_event);
- void do_menu(long command);
-
- typedef pascal void (*track_control_filter_ptr_t)(ControlRecord**,short);
-
-
- Rect drag_rect;
-
- void make_intervals_window();
- void make_chord_window();
- void make_about_ear_training_window();
- void make_sing_interval_window();
- DEN_MOTHER_T interval_den_mother,chord_den_mother,about_ear_training_den_mother,
- chord_help_den_mother,about_chord_den_mother,sing_interval_den_mother;
- int which_complete_window(WindowPtr w);
- void do_update(EventRecord *my_event);
- void do_activate(EventRecord *my_event);
- void do_key(EventRecord *my_event);
- void select_initial_workout();
-
-
- //-------------------------------------------------------------
- void
- main()
- {
-
-
-
- init_mac_stuff();
-
- set_up_menus(MBAR_ID,APPLE_MENU_ID);
- watch_cursor();
- set_up_sound();
- arrow_cursor();
- normal_text_style();
-
-
- select_initial_workout();
-
- event_loop();
-
- //--should never drop through here, but just in case:
-
- wrap_it_up();
- }
-
- //... called at beginning of progra; can also be called later
- // to reinstall everything (without recalculating wave table
- void
- set_up_sound()
- {
- do_waveforms(my_snd_chan,4,0.15,chans_used,my_wave_table,
- temp_wave_table,WAVE_TABLE_SIZE);
- }
-
- void
- select_initial_workout()
- {
- DialogPtr my_dialog;
- short item_hit;
- my_dialog = GetNewDialog(SELECT_INITIAL_WORKOUT_MODAL_DLOG_ID,
- 0,(WindowPtr) -1);
- if (VALID_POINTER(my_dialog)) {
- ModalDialog(0,&item_hit);
- DisposDialog(my_dialog);
- switch(item_hit) {
- case 1: //-- chords
- make_chord_window();
- break;
- case 2: //-- intervals
- make_intervals_window();
- break;
- case 4: //-- no workout
- break;
- case 5: //-- quit
- wrap_it_up();
- break;
- case 6: //-- sing intervals
- make_sing_interval_window();
- break;
- }
- }
- }
-
- void
- set_volume()
- {
- DialogPtr my_dialog;
- short item_hit;
- short vol,z;
- int i;
- int get_current_volume(SndChannelPtr snd_chan);
- void set_volume(int new_volume,SndChannelPtr snd_chan);
- my_dialog = GetNewDialog(VOLUME_MODAL_DLOG_ID,
- 0,(WindowPtr) -1);
- /*
- vol = 7 & ((GetSysPPtr()->volClik)>>8);
- */
- vol = 0;
- vol = get_current_volume(my_snd_chan[0])/(512/8)-1;
- if (vol>=1 && vol<=7) SetDialogDefaultItem(my_dialog,(short) vol);
- if (VALID_POINTER(my_dialog)) {
- ModalDialog(0,&item_hit);
- DisposDialog(my_dialog);
- switch(item_hit) {
- case 1:
- case 2:
- case 3:
- case 4:
- case 5:
- case 6:
- case 7:
- vol = item_hit;
-
- #if 0
- z = GetSysPPtr()->volClik;
- z = (z & 0xf8ff) | (vol<<8);
- dispose_of_chans(chans_used,my_snd_chan);
- GetSysPPtr()->volClik = z;
- WriteParam(); //...cf InitUtil
- InitUtil();
- set_up_sound();
- #endif
-
- #if 1
- // The above stuff with the system parameter block didn't
- // work. Apparently there is some magic way of notifying
- // the os that you've changed the volume, but I can't figure
- // out what it is. Instead, force it to recalculate the
- // waveform, which is time-consuming:
-
- have_wave_table = 0;
- do_waveforms(my_snd_chan,4,0.15*vol/7.,chans_used,my_wave_table,
- temp_wave_table,WAVE_TABLE_SIZE);
- #endif
-
- // Doesn't work:
- #if 0
- for (i=0; i<chans_used; i++)
- set_volume(vol,my_snd_chan[i]);
- #endif
-
- break;
- case 8:
- break;
- }
- }
- }
-
- void
- wrap_it_up()
- {
- int i;
- for (i=0; i<n_windows; i++) {
- delete my_windows[i];
- }
- dispose_of_chans(chans_used,my_snd_chan);
- if (have_sample_storage) {
- if (VALID_HANDLE(sound_handle)) DisposHandle(sound_handle);
- have_sample_storage = 0;
- }
- ExitToShell();
- }
-
- void
- init_mac_stuff()
- {
- InitGraf(&thePort);
- init_random(); /* must do InitGraf first!!!!!! */
- InitFonts();
- FlushEvents(everyEvent,0);
- InitWindows();
- InitMenus();
- InitCursor();
- //if (OpenResFile("\pmy.rsrc") == -1)
- // bail_out("could not open resource file");
- resources_available = 1;
- drag_rect = thePort->portRect;
- TextSize((short) normal_font_size);
- TEInit();
- }
-
- void
- make_window(int dlog_resource_id,
- Str255 param_text0,
- Str255 param_text1,
- Str255 param_text2,
- Str255 param_text3,
- DEN_MOTHER_T *den_mother)
- {
- if (n_windows>=MAX_WINDOWS) return;
- ++n_windows;
- my_windows[n_windows-1] = new complete_window(dlog_resource_id,
- param_text0,param_text1,param_text2,param_text3,
- den_mother);
-
- if (!VALID_POINTER(my_windows[n_windows-1])
- || !my_windows[n_windows-1]->is_valid) {
- --n_windows;
- }
- }
-
- void
- remove_window(int which)
- {
- int i;
- if (which>=n_windows) return;
- if (VALID_POINTER(my_windows[which])) {
- delete my_windows[which];
- //-- destructor will call the den mother and
- // do a DisposDialog
- for (i=which; i<=n_windows-2; i++) {
- my_windows[i] = my_windows[i+1];
- }
- }
- --n_windows;
- }
-
- int
- which_complete_window(WindowPtr w)
- {
- int i;
- for (i=0; i<n_windows; i++) {
- if (my_windows[i]->the_window==w) return i;
- }
- return -1;
- }
-
- void
- event_loop()
- {
- EventRecord my_event;
- int valid;
- for (;;) {
- SystemTask();
- valid = GetNextEvent(everyEvent,&my_event);
- if (valid) {
- switch(my_event.what) {
- case keyDown:
- do_key(&my_event);
- break;
- case mouseDown:
- do_mouse_down(&my_event);
- break;
- case activateEvt:
- do_activate(&my_event);
- break;
- case updateEvt:
- do_update(&my_event);
- break;
- default:
- break;
- } //-- end switch
- } //-- end if valid
- } //-- end for (;;)
- }
-
- void
- do_key(EventRecord *my_event)
- {
- long menu_result;
- int is_menu;
- is_menu = 0;
- if ((my_event->modifiers & cmdKey)!=0) {
- menu_result = MenuKey((char) (my_event->message & charCodeMask));
- is_menu = (HiWord(menu_result)!=0);
- }
- if (is_menu) {
- do_menu(menu_result);
- }
- else {
- //-- handle keystrokes
- }
- }
-
- void
- do_update(EventRecord *my_event)
- {
- GrafPtr save_graf;
- WindowPtr window;
- int which;
- complete_window *the_complete_window;
- window = (WindowPtr) my_event->message;
- which = which_complete_window(window);
- if (which>=0) {
- GetPort(&save_graf);
- SetPort(window);
- BeginUpdate(window);
-
- EraseRect(&window->portRect);
- DrawControls(window);
-
- the_complete_window = my_windows[which];
- the_complete_window->whassup = complete_window_redraw;
- the_complete_window->the_event = my_event;
- (*(the_complete_window->den_mother))(the_complete_window);
-
- EndUpdate(window);
- SetPort(save_graf);
- }
- }
-
-
- void
- do_activate(EventRecord *my_event)
- {
- if (my_event->modifiers & 1)
- SetPort((WindowPtr) (my_event->message)); //--activate event
- else
- ; //--deactivate event
- }
-
- //------- watch out that memory doesn't move, orphaning mouse_window
- void
- do_mouse_down(EventRecord *my_event)
- {
- WindowPtr mouse_window;
- int which_part;
- which_part = FindWindow(my_event->where,&mouse_window);
- switch(which_part) {
- case inMenuBar:
- do_menu(MenuSelect(my_event->where));
- break;
- case inSysWindow:
- SystemClick(my_event,mouse_window);
- break;
- case inGoAway:
- {
- int which;
- complete_window *the_complete_window;
- which = which_complete_window(mouse_window);
- if (which != -1) {
- remove_window(which);
- }
- }
- break;
- case inContent:
- if (mouse_window != FrontWindow())
- SelectWindow(mouse_window);
- else
- do_controls(mouse_window,my_event->where,my_event);
- break;
- case inDrag:
- DragWindow(mouse_window,my_event->where,&drag_rect);
- break;
- default:
- break;
- }
- }
-
- void
- do_menu(long command)
- {
- int menu_id,item;
- menu_id = HiWord(command);
- item = LoWord(command);
-
- switch(menu_id) {
- case APPLE_MENU_ID:
- {
- unsigned char item_name[32];
- switch(item) {
- case 1:
- //-- about Ear Training
- make_about_ear_training_window();
- break;
- default:
- GetItem(GetMHandle((short) menu_id),(short) item,item_name);
- OpenDeskAcc(item_name);
- break;
- }
- }
- break;
- case FILE_MENU_ID:
- ExitToShell();
- break;
- case EDIT_MENU_ID:
- if (item<=6 && item!=2) {
- int which;
- if (!SystemEdit(item-1)) {
- //...returns 0 if we should handle it
- which = which_complete_window(FrontWindow());
- if (which != -1) {
- message_to_den_mother(my_windows[which],
- (void **) 0,(void *) 0,(int) item,"edit");
- }
- }
- }
- break;
- case WORKOUTS_MENU_ID:
- switch(item) {
- case 1:
- make_intervals_window();
- break;
- case 2:
- make_chord_window();
- break;
- case 3:
- make_sing_interval_window();
- break;
- }
- break;
- case OPTIONS_MENU_ID:
- switch(item) {
- case 1: //-- volume
- set_volume();
- break;
- }
- }
- HiliteMenu(0);
- }
-
- void
- do_controls(WindowPtr window,Point where,EventRecord *my_event)
- {
- int which;
- complete_window *the_complete_window;
- ControlHandle control;
-
- which = which_complete_window(window);
- if (which== -1) bail_out("unknown window in do_controls");
- the_complete_window = my_windows[which];
- if (!VALID_POINTER(the_complete_window)
- || !the_complete_window->is_valid
- || !VALID_POINTER(the_complete_window->den_mother))
- bail_out("window is garbage in do_controls");
-
- GlobalToLocal(&where);
- //---this assumes that the routine do_activate
- // has set the graf port to be _this_ window
- the_complete_window->part_code = FindControl(where,window,&control);
-
- if (!TrackControl(control,where,(track_control_filter_ptr_t) 0)) return;
-
- if (!the_complete_window->part_code) return;
- the_complete_window->part_number
- = FindDItem(window,where);
- if (the_complete_window->part_number == -1) return;
-
- the_complete_window->whassup = complete_window_action;
- the_complete_window->the_event = my_event;
- (*(the_complete_window->den_mother))(the_complete_window);
- }
-
- void
- make_chord_help_window()
- {
- if (!chord_help_window_exists) {
- make_window(CHORD_HELP_DLOG_ID,"\p","\p","\p","\p",
- &chord_help_den_mother);
- chord_help_window_exists = 1;
- }
- }
-
- void
- make_about_ear_training_window()
- {
- if (!about_ear_training_window_exists) {
- make_window(ABOUT_EAR_TRAINING_DLOG_ID,"\p","\p","\p","\p",
- &about_ear_training_den_mother);
- about_ear_training_window_exists = 1;
- }
- }
-
- void
- make_intervals_window()
- {
- if (!interval_window_exists) {
- make_window(INTERVAL_DLOG_ID,"\p","\p","\p","\p",
- &interval_den_mother);
- interval_window_exists = 1;
- }
- }
-
- void
- make_sing_interval_window()
- {
- if (!sing_interval_window_exists) {
- make_window(SING_INTERVAL_DLOG_ID,"\p","\p","\p","\p",
- &sing_interval_den_mother);
- sing_interval_window_exists = 1;
- }
- }
-
- void
- make_chord_window()
- {
- if (!chord_window_exists) {
- make_window(CHORD_DLOG_ID,"\p","\p","\p","\p",
- &chord_den_mother);
- chord_window_exists = 1;
- }
- }
-
-
- // should check if resources_available, and if so, use dialog box
- void
- bail_out(char *message)
- {
- SysBeep((short) 0);
- debug_print(message);
- wrap_it_up();
- }
-
-
- void
- set_up_menus(int resource_id,int apple_menu_id)
- {
- Handle mbar_handle;
- MenuHandle apple_menu;
- mbar_handle = GetNewMBar((short) resource_id);
- if (ResError()!=0 || !VALID_HANDLE(mbar_handle) )
- bail_out("error reading menu bar");
- SetMenuBar(mbar_handle);
- apple_menu = GetMHandle((short) apple_menu_id);
- if (!VALID_HANDLE(apple_menu) )
- bail_out("error getting apple menu");
- AddResMenu(apple_menu,'DRVR');
- DrawMenuBar();
- }
-
- void
- about_ear_training_den_mother(complete_window *my_complete_window)
- {
- int need_to_redraw,ready_to_update;
- GrafPtr save_graf;
-
- need_to_redraw = 0;
- ready_to_update = 0;
-
- switch(my_complete_window->whassup) {
- case complete_window_created:
- need_to_redraw = 1;
- break;
- case complete_window_redraw:
- need_to_redraw = 1;
- ready_to_update = 1; //-- main program does begin update & sets graf port
- break;
- case complete_window_action:
- break;
- case complete_window_erase:
- about_ear_training_window_exists = 0;
- return;
- }
-
- if (need_to_redraw) {
- if (!ready_to_update) {
- GetPort(&save_graf);
- SetPort(my_complete_window->the_window);
- }
- {
- short tt;
- Handle hh;
- Rect rr;
- unsigned char s[300];
- TextFont((short) newYork);
- GetDItem(my_complete_window->the_window,(short) 1,&tt,&hh,&rr);
- if (VALID_HANDLE(hh)) {
- GetIText(hh,s);
- SetIText(hh,s);
- }
- GetDItem(my_complete_window->the_window,(short) 2,&tt,&hh,&rr);
- if (VALID_HANDLE(hh)) {
- GetIText(hh,s);
- SetIText(hh,s);
- }
- TextSize((short) 10);
- GetDItem(my_complete_window->the_window,(short) 3,&tt,&hh,&rr);
- if (VALID_HANDLE(hh)) {
- GetIText(hh,s);
- SetIText(hh,s);
- }
- normal_text_style();
- }
- if (!ready_to_update) {
- SetPort(save_graf);
- }
- }//---end if need to redraw
-
- }
-
- void
- chord_help_den_mother(complete_window *my_complete_window)
- {
- int need_to_redraw,ready_to_update;
- GrafPtr save_graf;
-
- need_to_redraw = 0;
- ready_to_update = 0;
-
- switch(my_complete_window->whassup) {
- case complete_window_created:
- need_to_redraw = 1;
- break;
- case complete_window_redraw:
- need_to_redraw = 1;
- ready_to_update = 1; //-- main program does begin update & sets graf port
- break;
- case complete_window_action:
- break;
- case complete_window_erase:
- chord_help_window_exists = 0;
- return;
- }
-
- if (need_to_redraw) {
- if (!ready_to_update) {
- GetPort(&save_graf);
- SetPort(my_complete_window->the_window);
- }
- TextFont((short) geneva);
- {
- int i;
- short tt;
- Handle hh;
- Rect rr;
- unsigned char s[300];
- for (i=1; i<=7; i++) {
- GetDItem(my_complete_window->the_window,(short) i,&tt,&hh,&rr);
- if (VALID_HANDLE(hh)) {
- GetIText(hh,s);
- SetIText(hh,s);
- }
- }
- }
- normal_text_style();
- if (!ready_to_update) {
- SetPort(save_graf);
- }
- }//---end if need to redraw
-
- }
-
-